package ac.il.technion.c236369.hw4.core.queues;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import ac.il.technion.c236369.hw4.configuration.ServerConfig;
import ac.il.technion.c236369.hw4.core.ServerRequest;
import ac.il.technion.c236369.hw4.core.queues.exception.NotEnoughtPlaceInQueue;

/**
 * @author Artem Barger, Maxim Aizenshtein
 * 
 * Storage class to keep incoming request for further reading 
 * and handling.
 * 
 */
public class ServerRequestsQueue {
	private static final ServerRequestsQueue instance = new ServerRequestsQueue( );
	private final List<ServerRequest> queue = new ArrayList<ServerRequest>( );
	private final Logger log = Logger.getLogger( ServerRequestsQueue.class);
	private final ExecutorService pool = Executors.newFixedThreadPool( ServerConfig.getInstance().getProperties().getRequestQueue());
	public static final ServerRequest NULL_SERVER_REQUEST = new ServerRequest( null);
	
	private ServerRequestsQueue( ) {
		
	}
	
	public static synchronized ServerRequestsQueue getInstance( ) {
		return instance;
	}
	
	/**
	 * Add incoming request to the queue.
	 * If queue is full execute spinning thread, which will try
	 * to insert request in the queue until there will 
	 * be a free space for it. 
	 * @param request
	 */
	public synchronized void tryAdd( final ServerRequest request) {
		if ( queue.size( ) >= ServerConfig.getInstance().getProperties().getRequestQueue()) {
			log.info( "Requests queue size limit is exceeded, current queue size is: <" + queue.size( ) + ">");
			pool.execute( new InsertRequestQueue( request));
		}
		queue.add(queue.size( ), request);
	}

	
	/**
	 * Add incoming request to the queue.
	 * 
	 * @param request
	 * @throws NotEnoughtPlaceInQueue thrown whenever place limit for queue is exceed.
	 */
	public synchronized void add( final ServerRequest request) throws NotEnoughtPlaceInQueue {
		if ( queue.size( ) >= ServerConfig.getInstance().getProperties().getRequestQueue()) {
			log.info( "Requests queue size limit is exceeded, current queue size is: <" + queue.size( ) + ">");
			throw new NotEnoughtPlaceInQueue( );
		}
		queue.add(queue.size( ), request);
	}

	
	/**
	 * @return next request to handle from the queue, in
	 * case where there is no currently requests in the
	 * queue there is NULL_SERVER_REQUEST is returned.
	 */
	public synchronized ServerRequest get( ) {
		if ( queue.size() == 0) 
			return NULL_SERVER_REQUEST;
		return queue.remove(0);
	}
}
